package handler;

import bean.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import service.TestService;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import java.io.IOException;
import java.util.List;
import java.util.Objects;

/*
 * @Controller表示此类（AnnotationController）是一个控制器类
 * 此注解是@Component的特化，可以被组件扫描器（context:component-scan）扫描所在包时被扫描到
 * 此注解通常与@RequestMapping结合使用
 */
@Controller
/*
 * @RequestMapping用于将匹配指定地址的请求映射到相应的处理方法 此注解可以作用于类和方法
 */
@RequestMapping("/system")
public class AnnotationController {
    private final TestService service;

    // @Autowired表示将（构造函数，字段，setter方法或config方法标记为由Spring的依赖项注入工具自动装配）
    @Autowired
    public AnnotationController(@Qualifier(value = "service") TestService service) {
        this.service = service;
    }

    // @RequestMapping用于指定请求映射的地址，它还可以筛选允许的请求方法类型
    @RequestMapping(value = "/add", method = RequestMethod.POST)
    public String addEntity(
            // 将请求中名称为field2的参数（parameter）与字符串param2绑定，即：将前者的值赋予后者
            @RequestParam(name = "field2") String param2,
            HttpServletResponse resp,
            /*
             * RedirectAttributes用于请求重定向时存储的属性
             * 重定向的请求地址映射的控制器方法中的Model和ModelMap参数均可以获取重定向属性
             */
            RedirectAttributes reqMappingRedirAttrs) throws IOException {
        service.add(param2);
        /*
         * 添加常规属性同样可以起到效果，但这会在浏览器地址栏附带参数
         * 添加闪存属性，这些属性将在请求重定向后自动移除
         * 确保数据安全，不建议使用addAttribute方法添加属性
         */
        reqMappingRedirAttrs.addFlashAttribute("operate", "add");
        return "redirect:/system";
    }

    @RequestMapping(value = "/modify", method = RequestMethod.POST)
    public String modifyEntity(
            /*
             * mvc支持将请求中的多个参数自动装配至拥有相同成员属性名的处理器方法参数中
             * 例如当请求中包含名称为field1或field2的参数时，如果处理器方法中的某个参数所属类定义有field1和field2两个成员变量
             * 那么mvc就会自动将请求中名称为的field1和field2两个参数封装至这个方法参数中
             * 需要注意的是，这个方法参数的类必须定义有相应属性的get和set方法
             * 此参数将被自动封装入从请求中传递的field1和field2两个参数
             * 因为Test类中存在与它们同名的变量
             */
            Test test,
            RedirectAttributes reqMappingRedirAttrs)
            throws IOException {
        service.modify(test);
        // 添加闪存属性，这些属性将在请求重定向后自动移除
        reqMappingRedirAttrs.addFlashAttribute("operate", "modify");
        return "redirect:/system";
    }

    @RequestMapping(value = "/remove", method = RequestMethod.POST)
    public String removeEntity(
            /*
             * 自动装配原则不仅适用于引用数据类型，同样也适用于基本数据类型
             * 当请求中包含的某个参数的名称与处理器方法的某个参数名一致时，前者的值将被赋予后者
             * 由于请求中的所有参数都属于String类型，mvc支持将请求参数的值智能转换为合适类型的值
             */
            int field1,
            RedirectAttributes reqMappingRedirAttrs)
            throws IOException {
        service.remove(field1);
        // 添加闪存属性，这些属性将在请求重定向后自动移除
        reqMappingRedirAttrs.addFlashAttribute("operate", "remove");
        return "redirect:/system";
    }

    // value与path属性的作用是等价的
    @RequestMapping(value = "")
    public ModelAndView queryEntities(
            // 如果控制器方法中定义有ModelMap或Model参数，那么两者均可以获取重定向前的RedirectAttributes
            // 将名称为operate的模型属性（ModelAttribute）与字符串param绑定，即：将前者的值赋予后者
            @ModelAttribute("operate") String param,
            // 将请求中名称为kw的参数与字符串keywords绑定
            @RequestParam(value = "kw", required = false) String keywords,
            HttpServletRequest req) {
        /*
         * 另一种获取请求重定向前的闪存属性的方式
         * RequestContextUtils.getInputFlashMap(HttpServletRequest).get(String)
         */
        HttpSession session = req.getSession();
        List<Test> entities = null;
        // 如果请求对象中的kw参数值不为空
        if (Objects.nonNull(keywords) && !keywords.equals("")) {
            // 使用关键词执行查询并将该关键词存储至会话中
            entities = service.query(keywords);
            session.setAttribute("kw", keywords);
            // 否则，判断请求是否是经过重定向后的请求
        } else {
            // 获取名称为operate的模型属性的值
            String operate = param;
            // 如果指定模型属性（RedirectAttributes接口实例中的属性名）operate的值为空
            if (operate != null && !operate.equals("")) {
                // 如果operate的值等于add，modify或remove，则使用会话中储存的kw属性值进行语句查询
                if (operate.equals("add") || operate.equals("modify") || operate.equals("remove")) {
                    // 获取会话中的kw属性的值
                    String kw = (String) session.getAttribute("kw");
                    if (kw != null && !kw.equals("")) {// 如果会话中的kw属性的值不为空
                        entities = service.query(kw);
                    } else {
                        // 以空值为参数，执行查询
                        entities = service.query(null);
                    }
                }
            } else {
                entities = service.query(null);
                session.removeAttribute("kw");
            }
        }
        ModelAndView modelAndView = new ModelAndView("index");
        modelAndView.addObject("entities", entities);
        return modelAndView;
    }
}
